package com.aotain.coeus.unregistered;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.apache.log4j.Logger;

import com.aotain.coeus.unregistered.bean.IPGroup;
import com.aotain.common.CommonDB;
import com.aotain.common.CommonFunction;
import com.aotain.common.DBObject;
import com.aotain.common.DbPool;

/**
 * IP所属组搜索
 * @author Administrator
 *
 */
public class IPSearch2 implements Serializable{
	
	private static IPSearch2 _instance = null;
	
	private String _dbJson = "";
	
	private static ReadWriteLock lock = new ReentrantReadWriteLock(); 
	
	private static boolean _IsLoading = false;
	
	private DbPool dbPool = null;
	
	
	/**
	 * IP 配置父子MAP 父  xxx.xxx  子  xxx.xxx.xxx.xxx
	 */
	private HashMap<String,IPSub> 
		_IPMaps = new HashMap<String,IPSub>();
	
	private String _mushroomCenter = "";
	
//	/**
//	 * 父IP Long数组
//	 */
//	private Long[] _ParentIPs = new Long[]{};
	
	public static IPSearch2 getInstance(String dbJson)
	{
		if(_instance == null)
		{
			Lock writeLock = lock.writeLock();
			writeLock.lock();
			try
			{
				if(_instance == null)
					_instance = new IPSearch2(dbJson);
			}catch (Exception e) {
				Logger.getLogger(IPSearch2.class).error("Init IP DATABASE ERROR:" + e.getMessage() ,e);
			}
			finally
			{
				writeLock.unlock();  
				//return null;
			}
		}
		return _instance;
	}
	
	public IPSearch2(String dbJson)
	{
		_dbJson = dbJson;
		
		IPGroupMap();
		
	}
	
	private Long[] _IPs = new Long[]{};
	
	private Long[] _IPParents = new Long[]{};
	
	
	/**
	 * 加载IP配置到MAP中
	 * @return
	 */
	public void IPGroupMap()
	{
		
		Logger.getRootLogger().info("######----INIT IPGroup---#####");
		ResultSet rs = null;
		Connection con = null;
		PreparedStatement ps = null;
		int count = 0;
		try
		{
//			if(dbPool == null)
//				dbPool = new DbPool();
//			
//			con = dbPool.getConnJson(_dbJson);
			DBObject obj = DBObject.getObject(_dbJson);
			
			con = CommonDB.getConnection(obj.getDriverClassName(), obj.getUrl(), obj.getUserName(), obj.getPassword());
			ps=con.prepareStatement("SELECT STARTIP,ENDIP,NAME,GROUPID,ID FROM SDS_RC_CFG_IPSEGMENT ");
				       
			rs=ps.executeQuery();
			_IPs = new Long[rs.getRow()];
	        while(rs.next()){
	        	IPGroup ip = new IPGroup();
	        	ip.setStartIP(CommonFunction.ip2int(rs.getString("STARTIP")));
	        	ip.setEndIP(CommonFunction.ip2int(rs.getString("ENDIP")));
	        	ip.setGroupID(rs.getString("GROUPID"));
	        	ip.setName(rs.getString("NAME"));
	        	ip.setID(rs.getString("ID"));
//	        	ip.setCountryName(rs.getString("COUNTRY_NAME"));
//	        	ip.setProviceName(rs.getString("PROVINCE_NAME"));
//	        	ip.setCityName(rs.getString("CITY_NAME"));
//	        	
//	        	ip.setCountryID(rs.getInt("COUNTRY_ID"));
//	        	ip.setProviceID(rs.getInt("PROVINCE_ID"));
//	        	ip.setCityID(rs.getInt("CITY_ID"));
//	        	
//	        	ip.setLon(rs.getFloat("LON"));
//	        	ip.setLat(rs.getFloat("LAT"));
	        	
	        	String[] IPSub = rs.getString("STARTIP").split("\\.");
	        	
	        	//IP 的前两段
	        	String IPParent = IPSub[0] + "." + IPSub[1] + ".";
	        	
	        	
	        	
	        	if(_IPMaps.containsKey(IPParent))
	        	{
	        		IPSub ipsub = _IPMaps.get(IPParent);
	        		HashMap<Long,IPGroup> map = ipsub.getIPMap();
	        		map.put(ip.getStartIP(), ip);
	        	}
	        	else
	        	{
	        		HashMap<Long,IPGroup> map = new HashMap<Long, IPGroup>();
	        		map.put(ip.getStartIP(), ip);
	        		IPSub ipsub = new IPSub();
	        		ipsub.setIPMap(map);
	        		_IPMaps.put(IPParent, ipsub);
	        	}
	        	count++;
	        }
	        
	        _IPParents = new Long[_IPMaps.size()];
	        _IPs = new Long[count];
	        int num = 0;
	        
	        
	        
	        int IPParentArrayCount = 0;
	        for(Entry<String,IPSub> ipsub : _IPMaps.entrySet())
	        {
		        for(Entry<Long,IPGroup> ip : ipsub.getValue().getIPMap().entrySet())
		        {
		        	if(ip.getKey()!=null)
		        	{
			        	_IPs[num] = ip.getKey();
			        	num++;
		        	}
		        	else
		        	{
		        		_IPs[num] = 0L;
		        		Logger.getRootLogger().warn("###IP IS NULL### STARTIP:" + ip.getValue().getStartIP());
		        	}
		        }
		        String IPParentFull = ipsub.getKey() + "0.1";
		        //将一个IP区段的StartIP，存入数组，为之后的二分查找准备
		        _IPParents[IPParentArrayCount] = CommonFunction.ip2int(IPParentFull);
		        IPParentArrayCount++;
	        }
		}
		catch(Exception ex)
		{
			//System.out.println("getKeywordConfig:"+ex.getMessage());
			Logger.getRootLogger().error("###ADD IP DB###",ex);
		}
		finally
		{
			CommonDB.closeDBConnection(con, ps, rs);
		}
		//BubbleSort();//
		Logger.getRootLogger().info("IPs:"+_IPs.length);
		Logger.getRootLogger().info("IPParents:"+_IPParents.length);
		sort(_IPs);
		sort(_IPParents);
		

		//为每一个IP段对象排序编号
		for(int i=0;i<_IPs.length - 1;i++)
		{
			Long startip = _IPs[i];
			
			for(IPSub ipsub : _IPMaps.values())
			{
				HashMap<Long,IPGroup> map = ipsub.getIPMap();
				IPGroup ip = map.get(startip);
				if(ip != null)
				{
					ip.setNo(i);
				}
			}
		}
		
		//每个二级IP段确定开始IP序号和结束IP序号
		for(IPSub ipsub : _IPMaps.values())
		{
			int startindex = _IPs.length;
			int endindex = 0;
			for(IPGroup ip : ipsub.getIPMap().values())
			{
				if(ip.getNo() <= startindex)
					startindex = ip.getNo();
				if(ip.getNo() >= endindex)
					endindex = ip.getNo();
			}
			
			endindex = endindex + 1;
			
			if(startindex > endindex)
			{
				startindex = 0;
				endindex = _IPs.length;
			}
			
			ipsub.setStartIndex(startindex);
			ipsub.setEndIndex(endindex);
		}
		
//		if(!_mushroomCenter.isEmpty())
//		{
//			 Slave s = new Slave(_mushroomCenter.split(":",-1)[0],
//					  Integer.parseInt(_mushroomCenter.split(":",-1)[1]));
//			 s.SendAlarmLog("INFO", "ADD IP DB Success.");
//		}
		Logger.getRootLogger().info("######----END INIT IPGroup---#####");
	}
	
	private void sort(Long[] IPs) {
		
			for (int i = 0; i < IPs.length - 1; i++) {
				Long temp = IPs[i];
				int left = 0;
				int right = i-1;
				int mid = 0;
				while(left<=right){
					try
					{
						mid = (left+right)/2;
						if(temp<IPs[mid]){
							right = mid-1;
						}else{
							left = mid+1;
						}
					}
					catch(Exception ex)
					{
						String sLog = String.format("temp:%d i:%d mid:%d IPs[mid]:%d", 
								temp,i,mid,IPs[mid]);
						Logger.getRootLogger().error("######-SORT ERROR:"+sLog,ex);
					}
				}
				for (int j = i-1; j >= left; j--) {
					IPs[j+1] = IPs[j];
				}
				if(left != i){
					IPs[left] = temp;
				}
			}
		
		
	}
	
	/**
	 * 
	 * @param map
	 * @param IPs
	 * @param findIp
	 * @return
	 */
	public IPGroup getStartIP(String findIp)
	{
		
		try
		{
			if(_IPMaps == null)
			{
				Logger.getRootLogger().warn("#######Init IPGroup Exception####Map is NULL#####");
				return null;
			}
			
			//先 按照 父 检索
			String[] ips = findIp.split("\\.");
			String parentip = ips[0] + "." + ips[1] + ".";
			IPGroup IP = null;
			
			IPSub sub = _IPMaps.get(parentip);
			if(sub != null)
			{//直接匹配到二级IP段
				Long startip = getStartIP(_IPs,findIp,sub.getStartIndex(),sub.getEndIndex());
				IP = sub.getIPMap().get(startip);
			}
			else
			{
				//如果没有找到这个父IP，则在父IP数组中查找距离最近的那个父IP
				Long lParentIP = getStartIP(_IPParents, parentip + "0.1");
				String sParentIP = CommonFunction.int2ip(lParentIP); 
				String ipSeg[] = sParentIP.split("\\.");
				IPSub sub2 = _IPMaps.get(ipSeg[0]+"."+ipSeg[1] + ".");
				if(sub2 != null)
				{
					//String ipSeg = ips[0] + "." + ips[1] + "." + ips[2] + ".0";
					//2016-06-12 修改BUG 将当前检索IP 带入到 二级段中查询
					Long startip = getStartIP(_IPs, findIp,
							sub2.getStartIndex(),sub2.getEndIndex());
					IP = sub2.getIPMap().get(startip);
					if(IP == null)
					{
						String slog = String.format("##[%s]GET IP:%s",findIp, CommonFunction.int2ip(startip));
						Logger.getLogger(IPSearch2.class).debug(slog);
						for(IPGroup ipobj1: sub2.getIPMap().values())
						{
							slog = String.format("##[%s]STARTIP:%s",findIp, CommonFunction.int2ip(ipobj1.getStartIP()));
							Logger.getLogger(IPSearch2.class).debug(slog);
						}
						
						for(int i = sub2.getStartIndex();i<=sub2.getEndIndex();i++)
						{
							slog = String.format("##[%s]IPs %d:%s",findIp, i, CommonFunction.int2ip(_IPs[i]));
							Logger.getLogger(IPSearch2.class).debug(slog);
						}
						
						slog = String.format("##IP:%s-> ParentIP:%s", findIp, parentip);
						Logger.getLogger(IPSearch2.class).debug(slog);
					}
				}
				else
				{
					String info = String.format("##Not Match IP[%s] Near Parent[%s]",
							findIp,sParentIP);
					Logger.getLogger(IPSearch2.class).info(info);
				}
			}
			
			
			return IP;
		}
		catch(Exception ex)
		{
			//ex.printStackTrace();
			String err = String.format("IPGroup getStartIP ERROR,IP[%s],Map Size[%d]", findIp,_IPs.length);
			Logger.getRootLogger().error(err,ex);
			return null;
		}
	}
	
	/**
	 * 二分查找
	 * @param IPs
	 * @param findIp
	 * @return
	 */
	public Long getStartIP(Long[] IPs,String findIp)
	{
		return getStartIP(IPs,findIp,0,IPs.length - 1);
	}
	
	/**
	 * 二分查找
	 * @param IPs
	 * @param findIp
	 * @return
	 */
	private Long getStartIP(Long[] IPs,String findIp,int begin, int tail)
	{
		Long ip = 0L;
		Long searchIP = CommonFunction.ip2int(findIp);
		int start = begin;  
        int end= tail;//IPs.length - 1; 
        int middle = 0;
        Long middleValue = 0l;
//        int count = 0;//循环次数
        while(start<=end)  
        {
            //中间位置  
            middle = (start+end)/2;    //相当于(start+end)/2  
            //中值  
            middleValue = IPs[middle];  
              
            if(searchIP == middleValue)  
            {  
                //等于中值直接返回  
                return middleValue;  
            }  
            else if( searchIP < middleValue)  
            {  
                //小于中值时在中值前面找  
                end=middle-1;  
            }  
            else  
            {  
                //大于中值在中值后面找  
                start = middle + 1;
            }  
            
//            count++;
        } 
        
//        String slog = String.format("##[%s]getStartIP.while.count=%d start:%d end:%d", 
//        		findIp, count, begin, tail);
//        Logger.getLogger(IPSearch.class).info(slog);
        
        
        //一般情况不能直接找到,在搜索完成后，当前的中值位置，中值，记录下来
        if(searchIP > middleValue)
        {
        	ip = middleValue;
        }
        else
        {
        	if(middle > IPs.length)
        	{
        		ip = IPs[IPs.length];
        	}
        	else if(middle == 0)
        	{
        		ip = IPs[0];
        	}
        	else
        	{
        		ip = IPs[middle - 1];
        	}
        }
		
		return ip;
	}

}

class IPSub implements Serializable
{
	private String _ParentIP;
	
	public void setParentIP(String parentIP)
	{
		this._ParentIP = parentIP;
	}
	
	public String getParentIP()
	{
		return this._ParentIP;
	}
	
	public HashMap<Long,IPGroup> _IPMap;
	
	public void setIPMap(HashMap<Long,IPGroup> ipmap)
	{
		this._IPMap = ipmap;
	}
	
	public HashMap<Long,IPGroup> getIPMap()
	{
		return this._IPMap;
	}
	
	private int _startindex;
	
	public void setStartIndex(int startindex)
	{
		this._startindex = startindex;
	}
	
	public int getStartIndex()
	{
		return this._startindex;
	}
	
	public int _endindex;
	
	public void setEndIndex(int endindex)
	{
		this._endindex = endindex;
	}
	
	public int getEndIndex()
	{
		return this._endindex;
	}
}